package com.campus.delivery.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Service
public class RedisService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 写入缓存 hash
     *
     * @param h  key
     * @param hk field
     * @param hv value
     */
    public void setHash(String h, String hk, String hv) {
        redisTemplate.opsForHash().put(h, hk, hv);
    }

    /**
     *
     */
    public <T, K> void setHashBatch(String h, Map<T, K> map) {
        redisTemplate.opsForHash().putAll(h, map);
    }

    /**
     * 获取缓存 hash
     *
     * @param h
     * @param obj
     * @param cls
     * @param <T>
     * @return
     */
    public <T> T getHash(String h, Object obj, Class<T> cls) {
        Object o = redisTemplate.opsForHash().get(h, obj);
        try {
            return objectMapper.readValue(o.toString(), cls);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }


    public Map<Object, Object> getHashAll(String h) {
        Map<Object, Object> entries = redisTemplate.opsForHash().entries(h);
        return entries;
    }

    /**
     * 判断hash结构中是否包含某字段(hexists)
     *
     * @param key
     * @param field
     * @return
     */
    public Boolean hexists(String key, String field) {
        return redisTemplate.opsForHash().hasKey(key, field);
    }

    /**
     * 获取hash结构中指定key的value，可以是多个fields
     *
     * @param key
     * @param fields
     * @return
     */
    public List<Object> hmget(String key, List<Object> fields) {
        List<Object> list = redisTemplate.opsForHash().multiGet(key, fields);
        return list;
    }

    public Object hget(String key, Object field) {
        return redisTemplate.opsForHash().get(key, field);
    }

    /**
     * 写入缓存
     *
     * @param key
     * @param value
     * @return
     */
    public boolean set(final String key, String value) {
        boolean result = false;
        try {
            ValueOperations<String, String> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public boolean setToJson(final String key, Object value) throws JsonProcessingException {
        return set(key, objectMapper.writeValueAsString(value));
    }

    /**
     * 写入缓存设置时效时间
     *
     * @param key
     * @param value
     * @param expireTime 秒
     * @return
     */
    public boolean set(final String key, String value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<String, String> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public boolean setToJson(final String key, Object value, Long expireTime) throws JsonProcessingException {
        return set(key, objectMapper.writeValueAsString(value), expireTime);
    }

    /**
     * 写入缓存设置时效时间
     *
     * @param key
     * @param value
     * @param expireTime 秒
     * @return
     */
    public boolean setNX(final String key, String value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<String, String> operations = redisTemplate.opsForValue();
            result = operations.setIfAbsent(key, value, expireTime, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public boolean setNXToJson(final String key, Object value, Long expireTime) throws JsonProcessingException {
        return setNX(key, objectMapper.writeValueAsString(value), expireTime);
    }

    public boolean expire(final String key, long expireTime) {
        return redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
    }

    /**
     * 批量删除对应的value
     *
     * @param keys
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }

    /**
     * 批量删除key
     *
     * @param pattern
     */
    public void removePattern(final String pattern) {
        Set<String> keys = redisTemplate.keys(pattern);
        if (keys.size() > 0)
            redisTemplate.delete(keys);
    }

    /**
     * 删除对应的value
     *
     * @param key
     */
    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }

    /**
     * 判断缓存中是否有对应的value
     *
     * @param key
     * @return
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 读取缓存
     *
     * @param key
     * @return
     */
    public String get(final String key) {
        String result = null;
        ValueOperations<String, String> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        return result;
    }

    public <T> T getFromJson(final String key, Class<T> cls) {
        Object object = get(key);
        if (object == null) {
            return null;
        }
        try {
            return objectMapper.readValue(object.toString(), cls);
        } catch (JsonProcessingException e) {
            throw new IllegalArgumentException("解析缓存数据失败");
        }
    }

    public <T> T getFromJson(final String key, TypeReference<T> typeRef) {
        Object object = get(key);
        if (object == null) {
            return null;
        }
        try {
            return objectMapper.readValue(object.toString(), typeRef);
        } catch (JsonProcessingException e) {
            throw new IllegalArgumentException("解析缓存数据失败");
        }
    }

    /**
     * 尝试获取分布式锁
     *
     * @param lockKey    锁的key
     * @param lockValue  锁的值（通常是唯一标识）
     * @param expireTime 锁的过期时间（秒）
     * @return 是否获取成功
     */
    public boolean tryLock(String lockKey, String lockValue, Long expireTime) {
        return setNX(lockKey, lockValue, expireTime);
    }

    /**
     * 释放分布式锁（使用Lua脚本保证原子性）
     *
     * @param lockKey   锁的key
     * @param lockValue 锁的值
     * @return 是否释放成功
     */
    public boolean releaseLock(String lockKey, String lockValue) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                       "return redis.call('del', KEYS[1]) " +
                       "else " +
                       "return 0 " +
                       "end";
        
        try {
            Object result = redisTemplate.execute((RedisCallback<? extends Object>) connection ->
                connection.eval(
                    script.getBytes(),
                    org.springframework.data.redis.connection.ReturnType.INTEGER,
                    1,
                    lockKey.getBytes(),
                    lockValue.getBytes()
                )
            );
            return result != null && (Long) result == 1L;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 生成订单抢单锁的key
     *
     * @param orderId 订单ID
     * @return 锁的key
     */
    public String getOrderGrabLockKey(String orderId) {
        return "order:grab:lock:" + orderId;
    }

}
